/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.cezary.butler.walili.client.mime;

import static pl.cezary.butler.walili.server.db.utils.UnitInterruptedException.isInterrupted;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;
import pl.cezary.butler.walili.client.ClientApp;
import pl.cezary.butler.walili.client.config.ClientConfiguration;
import pl.cezary.butler.walili.client.network.INetworkStats;
import pl.cezary.butler.walili.server.db.utils.UnitInterruptedException;

/**
 *
 * @author Czarek
 */
public class DownloadingMimeTypeAction extends MimeTypeAction{

    private static final ClientConfiguration config = ClientConfiguration.getInstance();
    private static final Logger log = Logger.getLogger(DownloadingMimeTypeAction.class.getName());
    private static INetworkStats stats;
    private final IFileNamingStrategy namingStrategy = new BasicFileNamingStrategy(new File(config.getTargetDownloadDirectory()));            

    private static INetworkStats getStats() {
        if (stats == null) {
            stats = ClientApp.initSpringContext().getBean(INetworkStats.class);
        }
        return stats;
    }

    private static final int BUF_SIZE = 512;

    @Override
    public boolean process(URLConnection connection) {
        boolean successfull = false;
        final URL url = connection.getURL();
        final File outputFile = namingStrategy.getOutputFile(url);
        File tmpOutFile = null;
        if (testAndPrepareFiles(outputFile)) {
            return true;//failed but due to local error;
        }
        if (outputFile.exists()) {
            log.log(Level.WARNING, "File {0} exists decided to not continue!!!!", outputFile);
            return true;
        }
        log.log(Level.INFO, "Dowloading file for url {0}", url);
        InputStream input = null;
        OutputStream out = null;
        try {
            tmpOutFile = File.createTempFile("jdo", ".tdl", namingStrategy.getBaseDir());
            input = connection.getInputStream();
            out = new FileOutputStream(tmpOutFile);
            final byte[] buffer = new byte[BUF_SIZE];
            int read;
            while ((read = input.read(buffer)) > 0&&!isInterrupted()) {
                getStats().read(read);
                out.write(buffer, 0, read);
            }
            successfull = true;

        } catch (UnitInterruptedException uie) {
            log.log(Level.INFO, "Downloading unit for {0} was interrupted",url);
        } catch (IOException ex) {
            log.log(Level.SEVERE, String.format("IO error while copying %s to %s", connection.getURL(), outputFile), ex);
            try {
                outputFile.delete();
            } catch (Exception e) {
                log.log(Level.WARNING, "Cleaning after error failed", e);
            }

        } finally {
            try {
                if (input != null) {
                    input.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                log.log(Level.SEVERE, "Error while closing streams", ex);
                throw new RuntimeException("Error while closing streams", ex);
            }
        }
        if (tmpOutFile != null) {
            if (successfull) {
                if(log.isLoggable(Level.FINE))
                    log.log(Level.FINE, "File {0} (in tmpfile {1}) downloaded, now renaming", new Object[]{outputFile, tmpOutFile});
                if (!tmpOutFile.renameTo(outputFile)) {//TODO zapisz do bazy hsql
                    log.log(Level.SEVERE, "App was unable to rename downloaded file {1} to {0} ", new Object[]{outputFile, tmpOutFile});
                    throw new RuntimeException("App was unable to rename downloaded");
                } else {
                    return true;
                }
            } else {
                if (!tmpOutFile.delete()) {
                    log.log(Level.WARNING, "App was unable to delete uncomplete file {0}", tmpOutFile);
                }
            }
        }
        return false;
    }

    private boolean testAndPrepareFiles(final File outputFile) {
        if (outputFile.exists()) {
            log.log(Level.WARNING, "File {0} exists", outputFile);
            if (outputFile.isDirectory()) {
                log.log(Level.SEVERE, "File {0} is a directory, cannot continue!");
                return true;
            }
        } else {
            final File parent = outputFile.getParentFile();
            if (!parent.exists()) {
                log.fine("Creating directory {0} for downloads");
                parent.mkdirs();
            } else if (!parent.isDirectory()) {
                log.warning("File {0} exists but isn't directory, cannot continue");
                return true;
            }
        }
        return false;
    }
}
